/*
 * Ex:			
 * File name:   FAT_fs.h
 *
 *  Created on: May 21, 2012
 *      Author: ayash
 *
 *
 * Descriptor:
 *
 */

#ifndef FAT_FS_H_
#define FAT_FS_H_

#include "FileSystem.h"
#include <cassert>
#include <sys/types.h>


class FAT_fs: public FileSystem
{

public:

	FAT_fs(unsigned int block_size,
		   unsigned int pointer_size,
	  	   unsigned int maximal_size,
	  	   result_t &result)

			:FileSystem(block_size, pointer_size, maximal_size)
	{

		if ( pointer_size == block_size)
		{
			result = ERROR_INVALID_ARGUMENTS;
		}
		else
		{
			result = OPERATION_SUCCESS;
		}
	}

	~FAT_fs() {}

	result_t calc_file_perf ( uint file_size, file_perf_t & file_perf )
	{
		assert( file_size );

		ulong sum_access = 0; // the sum of access blocks

		// number of data bytes that can be stored in a block
		uint num_bytes_block = _block_size - _pointer_size;

		/*
		 * here we calculate the average number of disk accesses per byte and
		 * the total number of blocks that are used for this file in a closed form
		 * (without a loop)
		 *
		 * the formula that we used here is as follow
		 *
		 * total = # full blocks + ( 1 if we have residue in the last block)
		 *
		 * avg = sum_access / file_size
		 *
		 * 	when sum_access =
		 *
		 * 	# byes in block * (1 + 2 + 3 + 4 + ... + # full blocks)
		 * 										+  ( residue * (# full blocks + 1) )
		 *
		 *	after using formula of sum of arithmetic series we get
		 *
		 * 	= (1/2) ( # byes in block * ( 1 + # full blocks ) * # full blocks )
		 * 				  +  ( residue * (# full blocks + 1) )
		 *
		 * and in order to preserve the precision we perform the devision only in the
		 * end (thats why we multiply by the second equation and divide it again in the
		 * end ).
		 *
		 */
		uint num_full_blocks = file_size / num_bytes_block;
		uint residue = ( file_size % num_bytes_block );

		/*
		 * we divide this calculation into couple of stages because the default middle
		 * result of the compiler is uint so we want to be on the safe side that we don't
		 * pass over uint maximum value.
		 */
		sum_access = num_bytes_block;
		sum_access *= (num_full_blocks + 1);
		sum_access *= num_full_blocks ;

		file_perf.num_block_used = num_full_blocks;

		if ( residue )
		{
			++file_perf.num_block_used;
			sum_access += ( ( residue << 1 ) * (num_full_blocks + 1) ) ;
		}

		file_perf.avg_block_access = ((double ) (sum_access)) / (file_size << 1);

		return OPERATION_SUCCESS;
	}

};

#endif /* FAT_FS_H_ */
